package com.scs.application.modules.device.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.modules.device.entity.DeviceCirculate;
import com.scs.application.modules.device.entity.DeviceCirculateItem;
import com.scs.application.modules.device.entity.DeviceCirculateSettings;
import com.scs.application.modules.device.enums.CostClassify;
import com.scs.application.modules.device.enums.DeviceBusMap;
import com.scs.application.modules.device.mapper.DeviceCirculateItemMapper;
import com.scs.application.modules.device.service.DeviceCirculateItemService;
import com.scs.application.modules.device.service.DeviceCirculateService;
import com.scs.application.modules.device.service.DeviceCirculateSettingsService;
import com.scs.application.modules.device.service.DeviceLedgerService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *  设备租赁、归还明细 服务实现类
 */
@Service
@AllArgsConstructor
public class DeviceCirculateItemServiceImpl extends BaseServiceImpl<DeviceCirculateItemMapper, DeviceCirculateItem> implements DeviceCirculateItemService {
    private DeviceLedgerService deviceLedgerService;
    private DeviceCirculateService deviceCirculateService;
    private DeviceCirculateSettingsService deviceCirculateSettingsService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateBatch(Collection<DeviceCirculateItem> entityList) {
        DeviceCirculate main = deviceCirculateService.getById(entityList.stream().findFirst().get().getCirculateId());
        BusinessException.throwErrorIf(main == null, "业务单不存在，请刷新重试");
        List<String> ledgerIdList = entityList.stream().map(DeviceCirculateItem::getLedgerId).collect(Collectors.toList());
        // 需要锁定库存的
        deviceLedgerService.lockBatch(
                ledgerIdList,
                StrUtil.format("业务锁定，业务单号: {}，业务日期: {}",main.getBusKey(), DateUtils.format(main.getBusDate(),DateUtils.YYYYMMDDHHMMSS_PATTER2))
        );

        Map<String,DeviceCirculateSettings> mapByLedgerId = deviceCirculateSettingsService.list(Wrappers.<DeviceCirculateSettings>query().in("ledger_id",ledgerIdList)).stream().collect(Collectors.toMap(DeviceCirculateSettings::getLedgerId, item -> item));
        BusinessException.throwErrorIf(ledgerIdList.size() != ObjectUtil.length(mapByLedgerId.keySet()), "共享设备缺失，请刷新重试");

        entityList.stream().forEach(item -> {
            item
                .setCirculateClassify(mapByLedgerId.get(item.getLedgerId()).getCirculateClassify())
                .setCostClassify(mapByLedgerId.get(item.getLedgerId()).getCostClassify())
                .setCostPrice(mapByLedgerId.get(item.getLedgerId()).getCostPrice())
            ;
        });
        return super.saveOrUpdateBatch(entityList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        Collection<DeviceCirculateItem> itemList =  this.listByIds(idList);
        if (ObjectUtil.length(itemList) > 0) {
            DeviceCirculate main = deviceCirculateService.getById(itemList.stream().findFirst().get().getCirculateId());
            BusinessException.throwErrorIf(main == null, "业务单据不存在");
            deviceLedgerService.unlockBatch(
                    itemList.stream().map(DeviceCirculateItem::getLedgerId).collect(Collectors.toList())
            );
        }
        return super.removeCascadeByIds(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(DeviceCirculateItem entity) {
        DeviceCirculate main = deviceCirculateService.getById(entity.getCirculateId());
        BusinessException.throwErrorIf(main == null, "业务单不存在，请刷新重试");

        // 租赁时，计算预计金额
        if (main.getBusType().equals(DeviceBusMap.DEVICE_CIRCULATE_OUT)) {
            Double expectAmount = 0d;
            switch (entity.getCostClassify()) {
                case CostClassify.second:{ // 按次
                    if (DateUtils.hourDiff(entity.getBorrowTime(), entity.getExpectTime()) <=0) {
                        BusinessException.throwError("借用时间[%s]应该早于预计归还时间[%s]",DateUtils.format(entity.getBorrowTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2),DateUtils.format(entity.getExpectTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2));
                    }
                    expectAmount = entity.getCostPrice();
                    break;
                }
                case CostClassify.hour:{ // 按小时
                    if (DateUtils.hourDiff(entity.getBorrowTime(), entity.getExpectTime()) <=0) {
                        BusinessException.throwError("借用时间[%s]应该早于预计归还时间[%s]",DateUtils.format(entity.getBorrowTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2),DateUtils.format(entity.getExpectTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2));
                    }
                    expectAmount = entity.getCostPrice() * DateUtils.hourDiff(entity.getBorrowTime(), entity.getExpectTime());
                    break;
                }
                case CostClassify.day:{ // 按天
                    if (DateUtils.dayDiff(entity.getBorrowTime(), entity.getExpectTime()) <=0) {
                        BusinessException.throwError("借用时间[%s]应该早于预计归还时间[%s]",DateUtils.format(entity.getBorrowTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2),DateUtils.format(entity.getExpectTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2));
                    }
                    expectAmount = entity.getCostPrice() * DateUtils.dayDiff(entity.getBorrowTime(), entity.getExpectTime());
                    break;
                }
                default:{
                    BusinessException.throwError("不支持的结算类型 %s",entity.getCostClassify());
                }
            }
            entity.setExpectAmount(expectAmount);
        } else if (main.getBusType().equals(DeviceBusMap.DEVICE_CIRCULATE_RETURN)) { // 归还时，更新实际金额
            Double costAmount = 0d;
            switch (entity.getCostClassify()) {
                case CostClassify.second:{ // 按次
                    if (DateUtils.hourDiff(entity.getBorrowTime(), entity.getReturnTime()) <=0) {
                        BusinessException.throwError("借用时间[%s]应该早于归还时间[%s]",DateUtils.format(entity.getBorrowTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2),DateUtils.format(entity.getReturnTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2));
                    }
                    costAmount = entity.getCostPrice();
                    break;
                }
                case CostClassify.hour:{ // 按小时
                    if (DateUtils.hourDiff(entity.getBorrowTime(), entity.getReturnTime()) <=0) {
                        BusinessException.throwError("借用时间[%s]应该早于归还时间[%s]",DateUtils.format(entity.getBorrowTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2),DateUtils.format(entity.getReturnTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2));
                    }
                    costAmount = entity.getCostPrice() * DateUtils.hourDiff(entity.getBorrowTime(), entity.getReturnTime());
                    break;
                }
                case CostClassify.day:{ // 按天
                    if (DateUtils.dayDiff(entity.getBorrowTime(), entity.getReturnTime()) <=0) {
                        BusinessException.throwError("借用时间[%s]应该早于归还时间[%s]",DateUtils.format(entity.getBorrowTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2),DateUtils.format(entity.getReturnTime(),DateUtils.YYYYMMDDHHMMSS_PATTER2));
                    }
                    costAmount = entity.getCostPrice() * DateUtils.dayDiff(entity.getBorrowTime(), entity.getReturnTime());
                    break;
                }
                default:{
                    BusinessException.throwError("不支持的结算类型 %s",entity.getCostClassify());
                }
            }
            entity.setCostAmount(costAmount);
        }

        return super.saveOrUpdate(entity);
    }
}